#region License

// This file is part of Grawlix.
// 
// Grawlix is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
// Grawlix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with Grawlix.  If not, see
// <http://www.gnu.org/licenses/>.

#endregion

using Grawlix.Geometry;
using Grawlix.Services.Rendering;

namespace Grawlix.Application.Gui
{
	/// <summary>
	/// Base class for all GUI controls.
	/// </summary>
	public abstract class Control
	{
		/// <summary>
		/// The parent of this control.
		/// </summary>
		private CompoundControl _parent;

		/// <summary>
		/// Gets or sets the parent of this control.
		/// </summary>
		/// <value>The parent of this control, which may be null.</value>
		public CompoundControl Parent
		{
			get { return _parent; }
			internal set { _parent = value; }
		}

		/// <summary>
		/// Determines whether this control is within another control.
		/// </summary>
		/// <param name="other">The control which may contain this
		/// control.</param>
		/// <returns>
		/// 	<c>true</c> if this control is within the other control;
		/// 	otherwise, <c>false</c>.
		/// </returns>
		public bool IsWithin(Control other)
		{
			if (Parent == null)
				return false;
			if (Parent == other)
				return true;
			return Parent.IsWithin(other);
		}

		/// <summary>
		/// Called when a character is resolved.
		/// </summary>
		/// <param name="character">The character.</param>
		public virtual void OnCharacter(char character)
		{
		}

		/// <summary>
		/// Called when a key is pushed down.
		/// </summary>
		/// <param name="code">The code of the key.</param>
		public virtual void OnKeyDown(int code)
		{
		}

		/// <summary>
		/// Called when a key is released.
		/// </summary>
		/// <param name="code">The code of the key.</param>
		public virtual void OnKeyUp(int code)
		{
		}

		/// <summary>
		/// Called when the mouse button is pushed down.
		/// </summary>
		/// <param name="position">The position of the mouse.</param>
		/// <param name="code">The code of the mouse button.</param>
		/// <param name="bounds">The boundaries of the control.</param>
		public virtual void OnMouseDown(Vector2 position, int code,
		                                Rect bounds)
		{
		}

		/// <summary>
		/// Called when the mouse enters the control.
		/// </summary>
		/// <param name="position">The position of the mouse.</param>
		/// <param name="bounds">The area of the control.</param>
		public virtual void OnMouseEnter(Vector2 position,
		                                 Rect bounds)
		{
		}

		/// <summary>
		/// Called when the mouse leaves the control.
		/// </summary>
		/// <param name="position">The last position of the mouse
		/// within the control.</param>
		/// <param name="bounds">The area of the control.</param>
		public virtual void OnMouseLeave(Vector2 position,
		                                 Rect bounds)
		{
		}

		/// <summary>
		/// Called when the mouse moves.
		/// </summary>
		/// <param name="position">The position of the mouse.</param>
		/// <param name="delta">The distance the mouse moved.</param>
		/// <param name="bounds">The boundaries of the control.</param>
		public virtual void OnMouseMove(Vector2 position,
		                                Vector2 delta, Rect bounds)
		{
		}

		/// <summary>
		/// Called when the mouse button is released.
		/// </summary>
		/// <param name="position">The position of the mouse.</param>
		/// <param name="code">The code of the mouse button.</param>
		/// <param name="bounds">The boundaries of the control.</param>
		public virtual void OnMouseUp(Vector2 position, int code,
		                              Rect bounds)
		{
		}

		/// <summary>
		/// Called when the mouse wheel is turned.
		/// </summary>
		/// <param name="position">The position of the mouse.</param>
		/// <param name="ticks">The number of ticks the wheel has
		/// turned.</param>
		/// <param name="bounds">The boundaries of the control.</param>
		public virtual void OnMouseWheel(Vector2 position,
		                                 int ticks, Rect bounds)
		{
		}

		/// <summary>
		/// Renders the control and all children to the specified
		/// device.
		/// </summary>
		/// <param name="device">The device to render to.</param>
		/// <param name="area">The area in which to render.</param>
		public abstract void Render(IRenderDevice device,
		                            Rect area);

		/// <summary>
		/// Tests the position of the mouse and returns the control
		/// under it.
		/// </summary>
		/// <param name="position">The position of the mouse.</param>
		/// <param name="bounds">The bounds of this control.</param>
		/// <returns>The control the mouse is pointing to.
		/// </returns>
		public virtual TestMouseResult TestMousePosition(
			Vector2 position, Rect bounds)
		{
			return new TestMouseResult
				{Position = position, Bounds = bounds, Focus = this};
		}
	}
}